#include "ai_talk_impl.h"
#include "ai_talk_ota.h"
#include "utils_log.h"
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
#include <thread>      // 用于 std::thread
#include <chrono>      // 用于 std::this_thread::sleep_for
#include <arpa/inet.h> // For htons, htonl (was in websocket_protocol.cc)
#include <curl/curl.h> // Added curl include
#include <sstream>     // For FetchWebsocketConfigFromOta response
#include <cstddef>     // For offsetof
#include "ai_talk_diagnosis.h"

// Placeholder for OPUS frame duration, adjust as needed
const int OPUS_FRAME_DURATION_MS = 20;

// Define a reasonable buffer size for WebSocket frames
#define WS_BUFFER_SIZE 16384 // 16KB buffer size

// Placeholder for Lang strings, replace with actual localization
namespace Lang {
namespace Strings {
const char *SERVER_ERROR = "Server error";
const char *SERVER_NOT_FOUND = "Server not found";
const char *SERVER_TIMEOUT = "Server timeout";
} // namespace Strings
} // namespace Lang

namespace El {
namespace AITalk {

IAITalk &IAITalk::GetInstance()
{
    return AITalkImpl::GetInstance();
}

AITalkImpl &AITalkImpl::GetInstance()
{
    static AITalkImpl s_aitalk;
    return s_aitalk;
}

AITalkImpl::AITalkImpl()
    : ws_curl_handle_(nullptr),                          // Initialized curl handle
      accessToken_("test-token"),                        // TODO: 从配置中获取
      deviceId_("00:0c:29:91:92:6a"),                    // 已设置固定MAC地址
      clientId_("669574f3-d8b2-49cb-81fb-d6808e12e55d"), // 使用固定的UUID值
      connected_(false),
      handshakeCompleted_(false),
      stopRequested_(false),
      server_sample_rate_(24000), // Default, will be updated by server hello
      server_frame_duration_(60), // Default, will be updated by server hello
      session_id_(""),            // Default, may be updated by server hello or config
      protocolVersion_(2),        // Changed from 3 to 2 to match header file
      busy_sending_audio_(false)
{

    Stop();
}

AITalkImpl::~AITalkImpl()
{
    Stop();
}

bool AITalkImpl::Start()
{
    if (workerThread_.joinable()) {
        EL_WARN("AI Talk 已启动或未正确停止。");
        return false;
    }

    AITalkOta::GetInstance().Start(ota_url_, deviceId_, clientId_);

    EL_INFO("正在启动 AI Talk 服务...");
    stopRequested_ = false;
    handshakeCompleted_ = false; // 重置握手状态
    connected_ = false;          // 重置连接状态

    try {
        workerThread_ = std::thread(&AITalkImpl::WorkerLoop, this);
    } catch (const std::system_error &e) {
        EL_ERROR("创建工作线程失败: {}", e.what());
        EL_ERROR("Failed to create worker thread: {}", e.what());
        return false;
    }

    AITalkDiagnosis::GetInstance().Start(); // 启动诊断服务

    return true;
}

void AITalkImpl::Stop()
{
    EL_INFO("正在停止 AI Talk 服务...");
    if (stopRequested_) {
        EL_INFO("已请求停止。");
        if (workerThread_.joinable()) {
        }
        return;
    }

    stopRequested_ = true;

    if (ws_curl_handle_) { // Check if curl handle exists for WebSocket
    }

    if (workerThread_.joinable()) {
        try {
            workerThread_.join();
        } catch (const std::system_error &e) {
            EL_ERROR("加入工作线程失败: {}", e.what());
        }
    }

    if (ws_curl_handle_) {
        curl_easy_cleanup(ws_curl_handle_);
        ws_curl_handle_ = nullptr;
    }

    EL_INFO("AI Talk 服务已停止。");
    connected_ = false;
    handshakeCompleted_ = false;
}

void AITalkImpl::WorkerLoop()
{
    EL_INFO("AI Talk 工作线程已启动。");
    if (!ConnectWebSocket()) { // Attempt to connect using Curl
        EL_ERROR("WebSocket 连接失败。工作线程正在退出。");
        EL_ERROR("WebSocket connection failed");
        connected_ = false;
        handshakeCompleted_ = false;
        if (ws_curl_handle_) { // ws_curl_handle_ might be partially initialized
            curl_easy_cleanup(ws_curl_handle_);
            ws_curl_handle_ = nullptr;
        }
        return;
    }

    connected_ = true;  // Mark as connected
    SendHelloMessage(); // Send initial hello

    char buffer[WS_BUFFER_SIZE]; // Define a buffer for receiving WebSocket frames
    size_t nread;
    const struct curl_ws_frame *meta;
    CURLcode recv_res;

    while (!stopRequested_ && connected_ && ws_curl_handle_) { // Loop while not stopped and connected
        recv_res = curl_ws_recv(ws_curl_handle_, buffer, sizeof(buffer) - 1, &nread, &meta);
        if (recv_res == CURLE_OK) {
            buffer[nread] = 0; // Null-terminate the received data
            EL_INFO("curl_ws_recv 成功，接收到 {} 字节，帧类型: {}", nread,
                     meta->flags & CURLWS_TEXT     ? "文本"
                     : meta->flags & CURLWS_BINARY ? "二进制"
                     : meta->flags & CURLWS_CLOSE  ? "关闭"
                     : meta->flags & CURLWS_PING   ? "PING"
                     : meta->flags & CURLWS_PONG   ? "PONG"
                                                   : "未知");

            if (meta->flags & CURLWS_TEXT) {
                HandleServerMessage(buffer, nread);
            } else if (meta->flags & CURLWS_BINARY) {
                EL_INFO("接收到二进制数据 ({} 字节)", nread);
            } else if (meta->flags & CURLWS_CLOSE) {
                EL_INFO("WebSocket CLOSE frame received. Reason: {}", std::string(buffer, meta->bytesleft));
                connected_ = false;
                handshakeCompleted_ = false;
                break;
            } else if (meta->flags & CURLWS_PING) {
                EL_INFO("Received PING, curl will auto-reply with PONG.");
            } else if (meta->flags & CURLWS_PONG) {
                EL_INFO("Received PONG.");
            }

        } else if (recv_res == CURLE_AGAIN) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Small delay
        } else if (recv_res == CURLE_GOT_NOTHING && meta && (meta->flags & CURLWS_CLOSE)) {
            EL_INFO("WebSocket CLOSE frame (CURLE_GOT_NOTHING with close flag)");
            connected_ = false;
            handshakeCompleted_ = false;
            break;
        } else {
            EL_ERROR("curl_ws_recv() 失败: {} (代码: {})", curl_easy_strerror(recv_res), (int)recv_res);

            // 当 recv_res 不是 CURLE_OK, CURLE_AGAIN, 或 CURLE_GOT_NOTHING (CLOSE) 时，
            // meta 指针的有效性未定义，不应解引用 meta->flags
            const char* message_type_str = "错误/未知";
            if (meta && (recv_res == CURLE_OK || recv_res == CURLE_GOT_NOTHING)) {
                 // 仅在 recv_res 为 OK 或 GOT_NOTHING (通常有关闭帧信息) 时尝试读取 meta->flags
                message_type_str = (meta->flags & CURLWS_TEXT)     ? "文本"
                                 : (meta->flags & CURLWS_BINARY) ? "二进制"
                                 : (meta->flags & CURLWS_CLOSE)  ? "关闭"
                                 : (meta->flags & CURLWS_PING)   ? "PING"
                                 : (meta->flags & CURLWS_PONG)   ? "PONG"
                                                                 : "未知";
            }

            EL_ERROR("WebSocket状态: 连接={}, 握手完成={}, 消息类型={}", connected_ ? "是" : "否",
                      handshakeCompleted_ ? "是" : "否", message_type_str);
            connected_ = false;
            handshakeCompleted_ = false;
            break;
        }
    }

    if (ws_curl_handle_) {
        if (connected_) { // If still marked connected, try to send a close frame
        }
    }

    connected_ = false; // Ensure disconnected state
    handshakeCompleted_ = false;

    EL_INFO("AI Talk 工作线程已结束。");
}

// int AITalkImpl::InitializeLws() { ... } // Removed LWS function

// Placeholder for the new ConnectWebSocket method
bool AITalkImpl::ConnectWebSocket()
{
    if (ws_curl_handle_) {
        EL_WARN("ConnectWebSocket called but ws_curl_handle_ already exists. Cleaning up first.");
        curl_easy_cleanup(ws_curl_handle_);
        ws_curl_handle_ = nullptr;
    }

    ws_curl_handle_ = curl_easy_init();
    if (!ws_curl_handle_) {
        EL_ERROR("curl_easy_init() failed for WebSocket.");
        return false;
    }

    bool use_ssl = true; // 默认使用SSL
    std::string ws_url = serverAddress_;

    EL_INFO("尝试连接到 WebSocket: {}", ws_url.c_str());

    curl_easy_setopt(ws_curl_handle_, CURLOPT_URL, ws_url.c_str());

    struct curl_slist *headers = nullptr;
    std::string protocol_version_str = "Protocol-Version: " + std::to_string(protocolVersion_);
    headers = curl_slist_append(headers, protocol_version_str.c_str());
    std::string device_id_str = "Device-Id: " + deviceId_;
    headers = curl_slist_append(headers, device_id_str.c_str());
    std::string client_id_str = "Client-Id: " + clientId_;
    headers = curl_slist_append(headers, client_id_str.c_str());
    if (!accessToken_.empty()) {
        std::string auth_header_val = accessToken_;
        if (auth_header_val.find(" ") == std::string::npos) {
            auth_header_val = "Bearer " + auth_header_val;
        }
        std::string auth_str = "Authorization: " + auth_header_val;
        headers = curl_slist_append(headers, auth_str.c_str());
    }

    if (headers) {
        curl_easy_setopt(ws_curl_handle_, CURLOPT_HTTPHEADER, headers);
    }
    curl_easy_setopt(ws_curl_handle_, CURLOPT_CONNECT_ONLY, 2L);

    if (use_ssl) {
        curl_easy_setopt(ws_curl_handle_, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(ws_curl_handle_, CURLOPT_SSL_VERIFYHOST, 0L);
    }

    curl_easy_setopt(ws_curl_handle_, CURLOPT_CONNECTTIMEOUT_MS, 10000L); // 10 seconds

    curl_easy_setopt(ws_curl_handle_, CURLOPT_VERBOSE, 1L);

    CURLcode res = curl_easy_perform(ws_curl_handle_);

    if (headers) {
        curl_slist_free_all(headers); // Free the headers list
    }

    if (res != CURLE_OK) {
        EL_ERROR("curl_easy_perform() for WebSocket connection failed: {}", curl_easy_strerror(res));
        EL_ERROR("WebSocket connect perform failed: {}", curl_easy_strerror(res));
        if (ws_curl_handle_) {
            curl_easy_cleanup(ws_curl_handle_);
            ws_curl_handle_ = nullptr;
        }
        return false;
    }

    long response_code;
    curl_easy_getinfo(ws_curl_handle_, CURLINFO_RESPONSE_CODE, &response_code);

    char *effective_url = nullptr;
    if (curl_easy_getinfo(ws_curl_handle_, CURLINFO_EFFECTIVE_URL, &effective_url) == CURLE_OK && effective_url) {
        EL_INFO("有效连接URL: {}", effective_url);
    }

    EL_INFO("WebSocket连接已建立成功，HTTP响应码: {}", response_code);
    EL_INFO("WebSocket connection established successfully (curl_easy_perform completed).");
    return true;
}

void AITalkImpl::SendHelloMessage()
{
    if (!ws_curl_handle_ || !connected_) { // Check curl handle and connected status
        EL_ERROR("无法发送 hello，WebSocket 未连接或句柄为空。");
        EL_ERROR("Server not found");
        return;
    }

    nlohmann::json helloMsg = {{"type", "hello"},
                               {"version", protocolVersion_}, // Use configured protocol version
                               {"transport", "websocket"},
                               {"audio_params",
                                {{"format", "opus"},
                                 {"sample_rate", 16000}, // Client preferred sending rate
                                 {"channels", 1},
                                 {"frame_duration", OPUS_FRAME_DURATION_MS}}}};
    SendJsonMessage(helloMsg);
    EL_INFO("已发送 hello 消消息。");
}

void AITalkImpl::HandleServerMessage(const char *data, size_t len)
{
    std::string msgStr(data, len);
    EL_INFO("收到消息: {}", msgStr.c_str());

    try {
        nlohmann::json receivedJson = nlohmann::json::parse(msgStr);
        if (receivedJson.contains("type")) {
            std::string type = receivedJson["type"];
            if (type == "hello") {
                EL_INFO("收到服务器 hello 响应。");
                ParseServerHello(receivedJson);
                handshakeCompleted_ = true;
                EL_INFO("WebSocket handshake completed.");
            } else if (type == "listen") {
                // 处理监听状态变更 (检测等)
                EL_INFO("收到 'listen' 消息: {}", receivedJson.dump(2).c_str());
            } else if (type == "tts") {
                // 处理 TTS 状态变更
                EL_INFO("收到 'tts' 消息: {}", receivedJson.dump(2).c_str());
            } else if (type == "abort") {
                EL_INFO("收到 'abort' 消息: {}", receivedJson.dump(2).c_str());
            } else if (type == "iot") {
                EL_INFO("收到 'iot' 消息: {}", receivedJson.dump(2).c_str());
            } else if (type == "llm") {
                // Handle emotion state
                EL_INFO("收到 'llm' (情感) 消息: {}", receivedJson.dump(2).c_str());
            } else {
                EL_WARN("收到未知消息类型: {}", type.c_str());
            }
        } else {
            EL_WARN("收到的 JSON 消息没有 'type' 字段。");
        }
    } catch (const nlohmann::json::parse_error &e) {
        EL_ERROR("解析 JSON 消息失败: {}。原始消息: {}", e.what(), msgStr.c_str());
    }
}

void AITalkImpl::SendJsonMessage(const nlohmann::json &jsonMsg)
{
    if (!ws_curl_handle_ || !connected_) { // Check curl handle
        EL_ERROR("无法发送 JSON，WebSocket 未连接或句柄为空。");
        return;
    }
    if (stopRequested_) {
        EL_WARN("已请求停止，不发送 JSON 消消息。");
        return;
    }

    std::string msgStr;
    try {
        msgStr = jsonMsg.dump();
    } catch (const std::exception &e) {
        EL_ERROR("将 JSON 转储到字符串失败: {}", e.what());
        return;
    }

    EL_INFO("尝试发送 JSON: {}", msgStr.c_str());
    size_t sent_len = 0;
    CURLcode res = curl_ws_send(ws_curl_handle_, msgStr.c_str(), msgStr.length(), &sent_len, 0, CURLWS_TEXT);
    if (res != CURLE_OK) {
        EL_ERROR("curl_ws_send (JSON) 失败，错误: {} (代码: {})", curl_easy_strerror(res), (int)res);
        // Consider closing connection or other error handling
    } else if (sent_len < msgStr.length()) {
        EL_WARN("curl_ws_send (JSON) 发送部分消息: {} / {} 字节。", sent_len, msgStr.length());
        // Handle partial write (e.g., queue remaining data or error out)
    } else {
        EL_INFO("成功发送 {} JSON 字节。", sent_len);
    }
}

void AITalkImpl::SendBinaryData(const unsigned char *data, size_t len, bool is_audio_opus)
{
    (void)is_audio_opus;
    if (!ws_curl_handle_ || !connected_ || !handshakeCompleted_) { // Check curl handle
        EL_ERROR("无法发送二进制数据，WebSocket 未就绪或握手未完成。");
        EL_ERROR("WebSocket not ready for binary data");
        return;
    }
    if (stopRequested_) {
        EL_WARN("已请求停止，不发送二进制数据。");
        return;
    }

    EL_INFO("尝试发送 {} 字节的二进制数据。", len);

    size_t sent_len = 0;
    CURLcode res = curl_ws_send(ws_curl_handle_, data, len, &sent_len, 0, CURLWS_BINARY);

    if (res != CURLE_OK) {
        EL_ERROR("curl_ws_send (二进制) 失败，错误: {}", curl_easy_strerror(res));
    } else if (sent_len < len) {
        EL_WARN("curl_ws_send (二进制) 发送部分消息: {} / {} 字节。", sent_len, len);
    } else {
        EL_INFO("成功发送 {} 二进制字节。", sent_len);
    }
}

void AITalkImpl::SendAudio(const AudioStreamPacket &packet)
{
    // if (!IsAudioChannelOpened()) {
    //     EL_ERROR("Cannot send audio, channel not open.");
    //     EL_ERROR("Audio channel not open for sending audio");
    //     return;
    // }

    busy_sending_audio_ = true;
    if (protocolVersion_ == 2) {
        std::vector<uint8_t> serialized_data(sizeof(BinaryProtocol2) + packet.payload.size());
        auto *bp2 = reinterpret_cast<BinaryProtocol2 *>(serialized_data.data());
        bp2->version = htons(static_cast<uint16_t>(protocolVersion_));
        bp2->type = htons(0); // 0 for OPUS
        bp2->reserved = 0;
        bp2->timestamp = htonl(packet.timestamp);
        bp2->payload_size = htonl(static_cast<uint32_t>(packet.payload.size()));
        memcpy(bp2->payload, packet.payload.data(), packet.payload.size());
        SendBinaryData(serialized_data.data(), serialized_data.size(), true);
    } else if (protocolVersion_ == 3) {
        std::vector<uint8_t> serialized_data(sizeof(BinaryProtocol3) + packet.payload.size());
        auto *bp3 = reinterpret_cast<BinaryProtocol3 *>(serialized_data.data());
        bp3->type = 0; // 0 for OPUS
        bp3->reserved = 0;
        bp3->payload_size = htons(static_cast<uint16_t>(packet.payload.size()));
        memcpy(bp3->payload, packet.payload.data(), packet.payload.size());
        SendBinaryData(serialized_data.data(), serialized_data.size(), true);
    } else { // Version 1 or unknown - send raw payload
        SendBinaryData(packet.payload.data(), packet.payload.size(), true);
    }
    busy_sending_audio_ = false;
}

void AITalkImpl::SendWakeWordDetected(const std::string &wake_word)
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send WakeWordDetected yet.");
        return;
    }
    nlohmann::json msg = {{"session_id", session_id_}, {"type", "listen"}, {"state", "detect"}, {"text", wake_word}};
    SendJsonMessage(msg);
}

void AITalkImpl::SendStartListening(ListeningMode mode)
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send StartListening yet.");
        return;
    }
    nlohmann::json msg = {{"session_id", session_id_}, {"type", "listen"}, {"state", "start"}};
    switch (mode) {
        case ListeningMode::kRealtime:
            msg["mode"] = "realtime";
            break;
        case ListeningMode::kAutoStop:
            msg["mode"] = "auto";
            break;
        case ListeningMode::kManualStop:
            msg["mode"] = "manual";
            break;
    }
    SendJsonMessage(msg);
}

void AITalkImpl::SendStopListening()
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send StopListening yet.");
        return;
    }
    nlohmann::json msg = {{"session_id", session_id_}, {"type", "listen"}, {"state", "stop"}};
    SendJsonMessage(msg);
}

void AITalkImpl::SendAbortSpeaking(AbortReason reason)
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send AbortSpeaking yet.");
        return;
    }
    nlohmann::json msg = {{"session_id", session_id_}, {"type", "abort"}};
    if (reason == AbortReason::kWakeWordDetected) {
        msg["reason"] = "wake_word_detected";
    }
    SendJsonMessage(msg);
}

void AITalkImpl::SendIotDescriptors(const std::string &descriptors_json_str)
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send IotDescriptors yet.");
        return;
    }
    try {
        nlohmann::json descriptors_json = nlohmann::json::parse(descriptors_json_str);
        if (!descriptors_json.is_array()) {
            EL_ERROR("IoT descriptors should be a JSON array string. Received: {}", descriptors_json_str.c_str());
            EL_ERROR("Invalid IoT descriptors format (not an array)");
            return;
        }

        for (const auto &descriptor : descriptors_json) {
            nlohmann::json message_root = {
                {"session_id", session_id_},
                {"type", "iot"},
                {"update", true},
                {"descriptors", nlohmann::json::array({descriptor})} // Send one by one
            };
            SendJsonMessage(message_root);
        }
    } catch (const nlohmann::json::parse_error &e) {
        EL_ERROR("Failed to parse IoT descriptors JSON: {}. Original string: {}", e.what(),
                  descriptors_json_str.c_str());
        EL_ERROR("Failed to parse IoT descriptors: {}", e.what());
    }
}

void AITalkImpl::SendIotStates(const std::string &states_json_str)
{
    if (!handshakeCompleted_) {
        EL_WARN("Handshake not completed, cannot send IotStates yet.");
        return;
    }
    try {
        // Validate if states_json_str is valid JSON (object or array)
        nlohmann::json states_json = nlohmann::json::parse(states_json_str);
        nlohmann::json msg = {
            {"session_id", session_id_},
            {"type", "iot"},
            {"update", true},
            {"states", states_json} // Embed the parsed JSON directly
        };
        SendJsonMessage(msg);
    } catch (const nlohmann::json::parse_error &e) {
        EL_ERROR("Failed to parse IoT states JSON: {}. Original string: {}", e.what(), states_json_str.c_str());
        EL_ERROR("Failed to parse IoT states: {}", e.what());
    }
}

// --- Helper Method Implementations ---
void AITalkImpl::ParseServerHello(const nlohmann::json &server_hello_json)
{
    EL_INFO("Parsing server hello: {}", server_hello_json.dump().c_str());
    try {
        if (server_hello_json.contains("transport")) {
            std::string transport = server_hello_json["transport"];
            if (transport != "websocket") {
                EL_ERROR("Unsupported transport from server: {}", transport.c_str());
                EL_ERROR("Unsupported transport: {}", transport);
                // Consider closing connection
                return;
            }
        }

        if (server_hello_json.contains("audio_params")) {
            const auto &audio_params = server_hello_json["audio_params"];
            if (audio_params.contains("sample_rate") && audio_params["sample_rate"].is_number_integer()) {
                server_sample_rate_ = audio_params["sample_rate"];
                EL_INFO("Server sample rate: {}", server_sample_rate_);
            }
            if (audio_params.contains("frame_duration") && audio_params["frame_duration"].is_number_integer()) {
                server_frame_duration_ = audio_params["frame_duration"];
                EL_INFO("Server frame duration: {} ms", server_frame_duration_);
            }
        }

        if (server_hello_json.contains("session_id") && server_hello_json["session_id"].is_string()) {
            session_id_ = server_hello_json["session_id"];
            EL_INFO("Session ID from server: {}", session_id_.c_str());
        }

    } catch (const nlohmann::json::exception &e) {
        EL_ERROR("Error parsing server hello JSON: {}", e.what());
        EL_ERROR("Error parsing server hello: {}", e.what());
    }
}

// bool AITalkImpl::FetchWebsocketConfigFromOta(const std::string &ota_url_param)
// {
// Function implementation moved to ai_talk_ota.cpp
// }

} // namespace AITalk
} // namespace El
